import io
import logging
from django.contrib.auth.models import User
from django.http import HttpResponse
from django.shortcuts import render

# Create your views here.
from django.views import View
from django_redis import get_redis_connection
from rest_framework.decorators import action
from config.fastdfsConfig import FASTDFS_SERVER_DOMAIN

from fdfs_client.client import Fdfs_client, get_tracker_conf

from rest_framework.response import Response
from rest_framework.status import HTTP_404_NOT_FOUND, HTTP_400_BAD_REQUEST, HTTP_500_INTERNAL_SERVER_ERROR
from rest_framework.viewsets import ReadOnlyModelViewSet, ModelViewSet
from rest_framework.permissions import *
from rest_framework_extensions.cache.mixins import CacheResponseMixin  # 缓存拓展 第三方库 别人写的
from config.dbs.redis_dev import LOGIN_KEY_TEMPLATE, EXPIRE_TIME
from utils.permission import ActiveUserPermission, wrap_permisssion, TeacherPermission, RootPermission, auto_user, \
    update_auto_user, destroy_auto_user
from .serializers import *
from utils.verifyUtil import ImageVerify

# 导入日志器
logger = logging.getLogger(__name__)
# 创建FastDFS客户端对象
tracker_path = get_tracker_conf('utils/fastdfs/client.conf')
client = Fdfs_client(tracker_path)


class ImageVerifyView(View):
    def get(self, request, uuid):
        imgVerify = ImageVerify()
        img, code = imgVerify.verify_code()  # 生成验证码图片方法
        img_bytes = io.BytesIO()
        img.save(img_bytes, format='PNG')
        img_bytes = img_bytes.getvalue()
        cache = get_redis_connection(alias='verify_codes')
        cache.set(LOGIN_KEY_TEMPLATE % uuid, code, EXPIRE_TIME)  # 将uuid对应验证码答案缓存到redis中

        return HttpResponse(img_bytes, content_type='image/png')


class UserViewSet(ReadOnlyModelViewSet):  # 只需要查单一数据，A用户不允许查看B,C,D用户信息
    queryset = User.objects.filter(is_active=1)  # 用户必须是激活状态，才可以使用接口
    serializer_class = UserSerializer
    permission_classes = [IsAuthenticated]  # 用户必须登陆才可以使用接口

    def get_serializer(self, *args, **kwargs):
        if self.action == 'password':
            return UpdatePasswordSerializer(*args, **kwargs)
        return self.serializer_class(*args, **kwargs)

    @wrap_permisssion(TeacherPermission)
    def list(self, request, *args, **kwargs):
        return ReadOnlyModelViewSet.list(self, request, *args, **kwargs)

    @wrap_permisssion(TeacherPermission)
    def retrieve(self, request, *args, **kwargs):
        return ReadOnlyModelViewSet.retrieve(self, request, *args, **kwargs)

    @wrap_permisssion(ActiveUserPermission)
    def update(self, request, pk):
        # 得到用户
        try:
            user = self.get_queryset().get(id=pk)
        except User.DoesNotExist:
            return Response(status=HTTP_404_NOT_FOUND)

        # 得到用户输入的数据进行反序列化
        user_serializer = self.get_serializer(user, data=request.data)
        # 校验
        user_serializer.is_valid(raise_exception=True)
        # 修改user表信息
        user_serializer.save()  # 修改instance，data

        # 判断是否传入详情信息
        user_detail = request.data.get('userdetail')  # 得到detail详情数据
        if user_detail:
            # 判断user有没有详情数据，判断数据库，
            if hasattr(user, 'userdetail'):
                # 如果有则修改
                user_detail_serializer = UserDetailSerializer(user.userdetail, data=user_detail)

            else:
                # 如果没有则创建
                user_detail['user'] = pk
                user_detail_serializer = UserDetailSerializer(data=user_detail)
            user_detail_serializer.is_valid(raise_exception=True)
            user_detail_serializer.save()

            user_serializer.data['userdetail'] = user_detail_serializer.data
        return Response(user_serializer.data)

    @action(methods=['post'], detail=True)
    def avatar(self, request, pk):
        # 得到操作的用户对象
        try:
            user = self.get_queryset().get(id=pk)
        except User.DoesNotExist:
            return Response(status=HTTP_404_NOT_FOUND)

        # 得到上传的文件数据
        file = request.FILES.get('file')
        # 判断是否有图片数据，文件类型是否是图片
        if not file or file.content_type not in ('image/jpeg', 'image/png', 'image/gif'):
            # 不是，返回客户端传入数据错误
            return Response(status=HTTP_400_BAD_REQUEST)

        # 是，交给fastdfs，存储到可用的storage服务上
        # 得到文件后缀名，如果没有后缀名则默认为png类型
        try:
            images_ext_name = file.name.split('.')[-1]
        except Exception as e:
            logger.info('图片拓展名异常：%s' % e)
            images_ext_name = 'png'

        # 上传图片数据，通过字节流
        try:
            upload_res = client.upload_by_buffer(file.read(), file_ext_name=images_ext_name)
        except Exception as e:
            logger.error('图片上传出现异常：%s' % e)
            return Response(status=HTTP_500_INTERNAL_SERVER_ERROR)
        else:
            if upload_res.get('Status') != 'Upload successed.':
                logger.warning('图片上传失败')
                return Response(status=HTTP_500_INTERNAL_SERVER_ERROR)

            # 得到返回的file_id
            image_name = upload_res.get('Remote file_id').decode()
            image_url = FASTDFS_SERVER_DOMAIN + image_name

            # 判断是否有详情表数据
            if hasattr(user, 'userdetail'):
                # 如果有，则修改头像字段，保存图片信息
                user_detail = user.userdetail  # 得到当前操作用户的用户详情模型对象
                user_detail.avatar = image_url
                user_detail.save()
            else:
                # 如果没有，则创建详情，保存图片信息
                UserDetail.objects.create(avatar=image_url, user=user)

            # 返回图片地址
            return Response({'data': image_url})

    @action(methods=['put'], detail=True)
    def password(self, request, pk):
        # 得到要操作的用户对象
        try:
            user = self.get_queryset().get(id=pk)
        except User.DoesNotExist:
            return Response(status=HTTP_404_NOT_FOUND)

        # 检查原密码是否正确
        serializer = self.get_serializer(data=request.data)
        serializer.is_valid(raise_exception=True)
        password = request.data['password']  # 得到客户端输入的原密码
        new_password = request.data['new_password']  # 得到客户端输入的新密码
        if user.check_password(password):
            # 正确修改密码
            user.set_password(new_password)
            user.save()
            return Response({'msg': '修改成功'})
        else:
            # 错误 返回提示密码错误
            return Response(status=HTTP_400_BAD_REQUEST)


class UserDviewSet(ModelViewSet):
    queryset = User.objects.all()
    serializer_class = UserSerializer

    @wrap_permisssion(RootPermission)
    def destroy(self, request, *args, **kwargs):
        return ModelViewSet.destroy(self, request, *args, **kwargs)


class AreaViewSet(CacheResponseMixin,
                  ModelViewSet):  # modelviewset具有RetrieveModelMixin，UpdateModelMixin，DestroyModelMixin，ListModelMixin方法
    queryset = Area.objects.all()
    serializer_class = AreaSerializer

    def get_queryset(self):
        if self.action == 'list':
            return Area.objects.filter(parent=None)
        else:
            return self.queryset

    def get_serializer_class(self):
        if self.action == 'retrieve':
            return ParentSerializer
        else:
            return AreaSerializer

    @wrap_permisssion(RootPermission)
    def create(self, request, *args, **kwargs):
        return ModelViewSet.create(self, request, *args, **kwargs)

    @wrap_permisssion(RootPermission)
    def update(self, request, *args, **kwargs):
        return ModelViewSet.update(self, request, *args, **kwargs)

    @wrap_permisssion(RootPermission)
    def destroy(self, request, *args, **kwargs):
        return ModelViewSet.destroy(self, request, *args, **kwargs)


class AddressViewSet(ModelViewSet):
    serializer_class = AddressSerializer
    permission_classes = [IsAuthenticated]

    def get_queryset(self):
        return self.request.user.address_set.filter(is_delete=False)

    @auto_user
    def create(self, request, *args, **kwargs):
        if self.get_queryset().count() >= 10:
            return Response({'detail': '收货地址数量超过上限'}, status=HTTP_400_BAD_REQUEST)
        return ModelViewSet.create(self, request, *args, **kwargs)

    @update_auto_user
    def update(self, request, *args, **kwargs):
        return ModelViewSet.update(self, request, *args, **kwargs)

    @destroy_auto_user
    def destroy(self, request, *args, **kwargs):
        return ModelViewSet.destroy(self, request, *args, **kwargs)
